home *** CD-ROM | disk | FTP | other *** search
/ HPAVC / HPAVC CD-ROM.iso / NCDC151.ZIP / NCDC.C next >
C/C++ Source or Header  |  1992-10-26  |  28KB  |  733 lines

  1. #include <ctype.h>
  2. #include <stdio.h>
  3. #include <stdlib.h>
  4. #include <string.h>
  5.  
  6. #if defined(MSDOS)
  7. #define DO_FOPEN 1                                             /* use fopen */
  8. #define ANSI_DECL           /* use ANSI C function declarations/definitions */
  9. #define FOPEN_R_ARG "rb"
  10. #define FOPEN_W_ARG "wb"
  11. #define EOL_STR "\r\n"                               /* end of line marking */
  12. #define SYSTEM_ID "MSDOS"
  13.  
  14. #elif defined(VMS)
  15. #include <file.h>                                   /* O_... flags for open */
  16. #include <unixio.h>                                       /* open prototype */
  17. #define DO_FOPEN 0                                     /* use open & fdopen */
  18. #define ANSI_DECL           /* use ANSI C function declarations/definitions */
  19. #define OPEN_R_ARG  O_RDONLY, 0
  20. #define OPEN_WN_ARG  O_WRONLY | O_TRUNC | O_CREAT, 0, "rat = cr","rfm = var"
  21. #define OPEN_WD_ARG  O_WRONLY | O_TRUNC | O_CREAT, 0, "rfm = var"
  22. #define FOPEN_R_ARG "r"
  23. #define FOPEN_W_ARG "w"
  24. #define EOL_STR "\n"                                 /* end of line marking */
  25. #define SYSTEM_ID "VMS"
  26.  
  27. #else                 /* don't use ANSI C function declarations/definitions */
  28. #include <fcntl.h>                                  /* O_... flags for open */
  29. #include <sys/types.h>
  30. #include <sys/stat.h>                               /* S_... flags for open */
  31. #define DO_FOPEN 0                                     /* use open & fdopen */
  32. #if !defined(O_RAW)
  33. #define O_RAW  0
  34. #endif
  35. #define OPEN_R_ARG  O_RAW | O_RDONLY, 0
  36. #define OPEN_WN_ARG  O_WRONLY | O_TRUNC | O_CREAT, S_IREAD | S_IWRITE
  37. #define OPEN_WD_ARG  O_RAW | O_WRONLY | O_TRUNC | O_CREAT, S_IREAD | S_IWRITE
  38. #define FOPEN_R_ARG "r"
  39. #define FOPEN_W_ARG "w"
  40. #define EOL_STR "\n"                                 /* end of line marking */
  41. #define SYSTEM_ID "UNIX"
  42.  
  43. #endif
  44.  
  45. /*----------------------- revision history ---------------------------------
  46.  * 26-10-92 (JAD): Pre/post encoding text used \n instead of \r\n for MSDOS.
  47.  * 08-04-92 (JAD): VMS specific help text restricted to VMS.
  48.  *          Documented NCDC.
  49.  * 01-05-91 (AM): added smaller buffer for VMS; added /s option:
  50.  *          Stream_LF decoding for VMS.
  51.  * 10-04-91 (JAD): added osize = 0 in decode; added get_start()
  52.  *          because continuation files received from SIMTEL don't
  53.  *          start with begin. When decodeing was expecting multiple
  54.  *          of four in last line, now computes # actually expected
  55.  *          (when encoding still writing multiple of four.
  56.  *  9-04-91 (JAD): changed VMS OPEN_W_ARG, added pre-ANSI C function
  57.  *          headers for UNIX.
  58.  *  8-04-91 (JAD): Introduced MSDOS/VMS/UNIX versions.
  59.  *  4-04-91 (JAD): Bug fix: table was not kept when found at top of
  60.  *          encoded file.
  61.  *--------------------------------------------------------------------------*/
  62.  
  63. /*=========================== global help ==================================*/
  64. char  sProgram[] = "NCDC";
  65. char  sVersion[] = "version 1.51";
  66. char  sAuthor[] = "J.A. Doornik.";
  67.  
  68. static char  *sUsage[]  = /* array of strings instead of one string for VAX */
  69. {
  70. #if defined(VMS)
  71.     "\nUsage:  NCDC infile [outfile] [/u] [/s] [/##]\n",
  72. #else
  73.     "\nUsage:  NCDC infile [outfile] [/u] [/##]\n",
  74. #endif
  75.     "Decodes if infile has no extension or extension ENC, XXE or UUE;",
  76.     "Encodes otherwise.\n",
  77.     "Encoding: uses XXencoding or UUencoding if /u is specified",
  78.     "\t  /## sets maximum outfile size to ## kilobytes",
  79.     "\t  Eg NCDC test.zip /50 could lead to",
  80.     "\t  test.enc, test.en2 and test.en3 being created.",
  81.     "Decoding: decoding method is derived from first encoded line.\n",
  82. #if defined(VMS)
  83.     "Decoded file defaults in Variable length format.",
  84.     "\t  /s  : decoded file in Stream_LF format.\n",
  85. #endif
  86.     "Example : ncdc test.         XXencode file test into test.enc",
  87.     "          ncdc test          XXdecode file test.enc into test",
  88.     NULL
  89. };
  90.  
  91. #define  FALSE 0
  92. #define  TRUE  !FALSE
  93. #define  byte  unsigned char
  94.  
  95. /*---------------- files and  internal buffer for in/output ----------------*/
  96. #define CONFIRM     0
  97. #define NO_CONFIRM  1
  98. #define IN_BUFLEN 20480
  99. #if defined(VMS)
  100. #define OUT_BUFLEN 512                                         /* 0.5K buffer */
  101. #else
  102. #define OUT_BUFLEN 20480                                       /* 20K buffer */
  103. #endif
  104. byte    Stream_LF = FALSE;        /* indicates Stream_LF decoded file on VAX */
  105. char    sInbuf[IN_BUFLEN], sOutbuf[OUT_BUFLEN];
  106. char    sOutfile[80] = "", sInfile[80] = "";
  107. FILE   *FILEin, *FILEout;
  108.  
  109. /*-------------------- UUencode information --------------------------------*/
  110. char    sUUtable[]                                       /* character table */
  111.      = "`!\"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_";
  112. int     iUUlen = 'M';
  113.  
  114. /*-------------------- XXencode information --------------------------------*/
  115. char    sXXtable[]                                       /* character table */
  116.      = "+-0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
  117. int     iXXlen = 'h';
  118.  
  119. /*---------------------- coding information --------------------------------*/
  120. #define ERROR    0
  121. #define WARNING  1
  122. #define MESSAGE  2
  123. #define NCODE    0
  124. #define DCODE    1
  125.  
  126. #define BIT6MASK 0x3F
  127.  
  128. #define INLEN  45   /* # chars in line to be encoded, must be multiple of 3 */
  129. #define OUTLEN 60           /* INLEN original bytes is OUTLEN encoded bytes */
  130.  
  131. #define UNDEF_CH -2               /* value if ch undefined in character map */
  132.  
  133. char    sMethod[] = "XXencode";
  134. int     aiNNmap[257];                                   /* holds active map */
  135. int    *piNNmap = aiNNmap + 1;             /* now piNNmap[-1] == aiNNmap[0] */
  136.                                            /* assumed is that EOF equals -1 */
  137. int     iNNlen;                    /* # bytes in a full length encoded line */
  138. char    sDefault_ext[] = ".enc";                       /* default extension */
  139. int     cLine;                          /* current lineNumber in input file */
  140. int     chFirst = 0; /* first decoding char found in get_ouffname/get_start */
  141.                                                /* this is to avoid ungetc() */
  142. #define MAXLINELEN 80
  143. byte abLine[MAXLINELEN + 1];      /* input line, must be unsigned for <<,>> */
  144.  
  145.  
  146. /*--------------------------- message --------------------------------------*/
  147. #if defined(MSDOS) | defined(VMS)
  148. #include <stdarg.h>
  149.  
  150. void message(int level, int line, char *msg, ...)
  151. {
  152.     va_list args;
  153.  
  154.     printf("%s ", sProgram);
  155.     if (line) printf("%s (%d) ", sInfile, line);
  156.  
  157.     if (level == ERROR)         printf("error: ");
  158.     else if (level == WARNING)  printf("warning: ");
  159.  
  160.     va_start(args, msg);                   /* args points to first argument */
  161.     vfprintf(stdout, msg, args);    va_end(args);
  162.     printf(".\n");
  163.  
  164.     if (level == ERROR)  exit(0);
  165. }
  166. #else
  167. #include <varargs.h>
  168.  
  169. message(level, line, va_alist)  int level, line; va_dcl
  170. {
  171.     va_list args;  char *msg;
  172.  
  173.     printf("%s ", sProgram);
  174.     if (line) printf("%s (%d) ", sInfile, line);
  175.  
  176.     if (level == ERROR)         printf("error: ");
  177.     else if (level == WARNING)  printf("warning: ");
  178.  
  179.     va_start(args);                         /* args points to format string */
  180.     msg = va_arg(args, char *);            /* args points to first argument */
  181.     vfprintf(stdout, msg, args);    va_end(args);
  182.     printf(".\n");
  183.  
  184.     if (level == ERROR)  exit(0);
  185. }
  186. #endif
  187. /*--------------------------- END message ----------------------------------*/
  188.  
  189.  
  190. /*------------------------- fbase/fext -------------------------------------
  191.  * fname = path + base + extension (incl. dot)
  192.  * fbase returns pointer to start of base.
  193.  * fext returns pointer to start of extension, or end of file name.
  194.  *--------------------------------------------------------------------------*/
  195. #if defined(ANSI_DECL)
  196.   char *fbase(char *fname)
  197. #else
  198.   char *fbase(fname)  char *fname;
  199. #endif
  200. {
  201.     char *s;
  202.  
  203.     if ( (s = strrchr(fname, '\\')) != NULL)
  204.         s++;                      /* points to first character after last \ */
  205.     else if ( (s = strrchr(fname, ':')) != NULL)
  206.         s++;                      /* points to first character after last : */
  207.     else
  208.         s = fname;                                 /* whole name, no : or \ */
  209. return(s);
  210. }
  211.  
  212. #if defined(ANSI_DECL)
  213.   char *fext(char *fname)
  214. #else
  215.   char *fext(fname)  char *fname;
  216. #endif
  217. {
  218.     char *s;
  219.  
  220.     if ( (s = strrchr(fname, '.')) == NULL)
  221.         s = fname + strlen(fname);            /* points to extension or end */
  222. return(s);
  223. }
  224. /*------------------------- END fbase/fext ---------------------------------*/
  225.  
  226.  
  227. /*------------------------------ fopen_r/fopen_w ---------------------------
  228.  * does low level or high level opening, according to value of DO_FOPEN
  229.  * MSC: fopen "wb" is at least 5 times faster than "w"
  230.  *--------------------------------------------------------------------------*/
  231. #if defined(ANSI_DECL)
  232.   FILE *fopen_r(char *sfi, char *ibuf)
  233. #else
  234.   FILE *fopen_r(sfi, ibuf)  char *sfi, *ibuf;
  235. #endif
  236. {
  237.     FILE *ifd = NULL;  int ifh;
  238.  
  239. #if DO_FOPEN
  240.     ifd = fopen(sfi, FOPEN_R_ARG);
  241. #else
  242.     if ( (ifh = open(sfi, OPEN_R_ARG)) != -1)
  243.         ifd = fdopen(ifh, FOPEN_R_ARG);
  244. #endif
  245.  
  246.     if (ifd == NULL)   message(ERROR, 0, "cannot open input file %s", sfi);
  247.     if (ibuf != NULL)  setvbuf(ifd, ibuf, _IOFBF, IN_BUFLEN);
  248.  
  249. return(ifd);
  250. }
  251.  
  252. #if defined(ANSI_DECL)
  253.   FILE *fopen_w(char *sfo, char *obuf, int confirm, int ncdc)
  254. #else
  255.   FILE *fopen_w(sfo, obuf, confirm, ncdc)  char *sfo, *obuf; int confirm, ncdc;
  256. #endif
  257. {
  258.     FILE *ofd = NULL;  int  yn, ofh;
  259.  
  260.     if (confirm == CONFIRM && (ofd = fopen(sfo, "r")) != NULL)
  261.     {
  262.         fprintf(stderr, "%s already exists", sfo);
  263.  
  264. #if !defined(VMS)                        /* VMS just makes a higher version */
  265.         fprintf(stderr, ", overwrite (Y/N)? ");
  266.         do
  267.         {   yn = getchar();  yn = toupper(yn);
  268.         }  while (yn != 'Y' && yn != 'N');
  269.         if (yn == 'N') message(ERROR, 0, "%s not overwritten", sfo);
  270. #else
  271.         fprintf(stderr, ".\n");
  272. #endif
  273.  
  274.         fclose(ofd);
  275.     }
  276.  
  277. #if DO_FOPEN
  278.     ofd = fopen(sfo, FOPEN_W_ARG);
  279. #else
  280.     if ( ncdc == DCODE && (Stream_LF == TRUE ) )
  281.         ofd = fopen(sfo, FOPEN_W_ARG);
  282.     else if ( (ncdc == NCODE && (ofh = open(sfo, OPEN_WN_ARG)) != -1)
  283.            || (ncdc == DCODE && (ofh = open(sfo, OPEN_WD_ARG)) != -1) )
  284.              ofd = fdopen(ofh, FOPEN_W_ARG);
  285. #endif
  286.  
  287.     if (ofd == NULL)   message(ERROR, 0, "cannot open output file %s", sfo);
  288.     if (obuf != NULL)  setvbuf(ofd, obuf, _IOFBF, OUT_BUFLEN);
  289.  
  290. return(ofd);
  291. }
  292. /*-------------------------- END fopen_r/fopen_w ---------------------------*/
  293.  
  294.  
  295. /*--------------------------- get_encmethod --------------------------------
  296.  * Determines the encoding method, and sets up the decoding info.
  297.  * Assumes that infile is at the start of the encoded text.
  298.  *--------------------------------------------------------------------------*/
  299. #if defined(ANSI_DECL)
  300.   void get_encmethod(FILE *infile, int notable)
  301. #else
  302.   get_encmethod(infile, notable)  FILE *infile; int notable;
  303. #endif
  304. {
  305.     int i, ch;
  306.  
  307.     chFirst = getc(infile);                /* peek ahead to get line length */
  308.  
  309.     if (notable)                               /* determine encoding method */
  310.     {   if (chFirst == iUUlen)
  311.         {   sMethod[0] = sMethod[1] = 'U';
  312.             for (i = 0; i < 64; i++)
  313.                 sXXtable[i] = sUUtable[i];        /* replace XXmap by UUmap */
  314.             iXXlen = iUUlen;
  315.         }
  316.         else if (chFirst != iXXlen)
  317.             message(ERROR, 0, "unknown encoding method");
  318.     }
  319.     else
  320.     {   sMethod[0] = sMethod[1] = 'U';       /* table -> call it UUencode */
  321.         iXXlen = chFirst;
  322.     }
  323.  
  324.     for (i = 0; i <= 255; i++)                       /* setup character map */
  325.         piNNmap[i] = UNDEF_CH;
  326.     for (i = 0; i < 64; i++)
  327.     {   ch = sXXtable[i];
  328.         if (piNNmap[ch] != UNDEF_CH)
  329.             message(ERROR, 0, "character %c already defined in table", ch);
  330.         else
  331.            piNNmap[ch] = i;
  332.     }
  333.     if (EOF != -1)  message(ERROR, 0, "EOF is not -1");
  334.     piNNmap[EOF] = EOF;
  335.  
  336.     iNNlen = piNNmap[iXXlen];           /* replace encoded value by # bytes */
  337. }
  338. /*--------------------------- END get_encmethod ----------------------------*/
  339.  
  340.  
  341. /*----------------------- get_outfname/get_start ---------------------------
  342.  * get_outfname gets the original name of the encoded file from the input
  343.  *   file. If a table is found, this is stored in sXXtable.
  344.  *   Determines encoding method.
  345.  * get_start locates the start in the next file
  346.  *--------------------------------------------------------------------------*/
  347. #if defined(ANSI_DECL)
  348.   void get_outfname(FILE *infile, char *infname, char *outfname)
  349. #else
  350.   get_outfname(infile,infname,outfname) FILE *infile;char *infname, *outfname;
  351. #endif
  352. {
  353.     int  i, notable = TRUE;
  354.  
  355.     cLine = 1;                         /* current line number in input file */
  356.  
  357.     while (TRUE)
  358.     {   if (fgets(abLine, MAXLINELEN, infile) == NULL)
  359.             break;                                /* EOF: break out of loop */
  360.         cLine++;
  361.  
  362.         if (strncmp(abLine, "begin", 5) == 0)           /* yes: begin found */
  363.         {   sscanf(abLine + 6, " %*s %s ", outfname);
  364.             get_encmethod(infile, notable);
  365.             return;
  366.         }
  367.         else if (strncmp(abLine, "table", 5) == 0)
  368.         {   notable = FALSE;
  369.             fgets(abLine, MAXLINELEN, infile);           /* 1st half of map */
  370.             fgets(abLine + 32, MAXLINELEN - 32, infile); /* 2nd half of map */
  371.             for (i = 0; i < 64; i++)
  372.                 sXXtable[i] = abLine[i];        /* replace XXmap by new map */
  373.         }
  374.         else if (strncmp(abLine, "charmap", 7) == 0)
  375.         {   notable = FALSE;
  376.             for (i = 0; i < 64; i++)
  377.                 sXXtable[i] = abLine[i + 8];    /* replace XXmap by new map */
  378.         }
  379.     }
  380.     message(ERROR, 0, "nothing to decode in file %s", infname);
  381. }
  382.  
  383. #if defined(ANSI_DECL)
  384.   FILE *get_start(char *infname)
  385. #else
  386.   FILE *get_start(infname)  char *infname;
  387. #endif
  388. {
  389.     int  ch, nobegin = TRUE;  FILE *infile;
  390.  
  391.     cLine = 1;                         /* current line number in input file */
  392.     chFirst = 0;
  393.     infile = fopen_r(infname, sInbuf);
  394.  
  395.     if ( (ch = getc(infile)) == iXXlen)   nobegin = FALSE;
  396.     while (nobegin)
  397.     {   abLine[0] = ch;
  398.         if (ch != '\n' && fgets(abLine + 1, MAXLINELEN, infile) == NULL)
  399.             break;                                /* EOF: break out of loop */
  400.         cLine++;
  401.         if (strncmp(abLine, "begin", 5) == 0)
  402.             nobegin = FALSE;
  403.         else if ( (ch = getc(infile)) == iXXlen)
  404.             nobegin = FALSE;
  405.     }
  406.     if (nobegin)
  407.         message(ERROR, 0, "nothing to decode in file %s", infname);
  408.     else if (ch == iXXlen)
  409.     {   chFirst = ch;
  410.         message(WARNING, cLine,
  411.             "line starting with \'%c\' found before \"begin\"", chFirst);
  412.     }
  413. return(infile);
  414. }
  415. /*----------------------- END get_outfname/get_start -----------------------*/
  416.  
  417.  
  418. /*------------------------- encode -----------------------------------------*/
  419. #if defined(ANSI_DECL)
  420.   int  encode_file(long *fsize, int mxlines)
  421. #else
  422.   int  encode_file(fsize, mxlines)  long *fsize; int mxlines;
  423. #endif
  424. {
  425.     byte *buf = abLine + 1; /* 1st char of abLine is quant., rest is buffer */
  426.     int  i, j, len, chbytes3;
  427.     int  nbytes3;       /* # decoded bytes (so 4 * nbytes / 3 when encoded) */
  428.  
  429.     chbytes3 = sXXtable[INLEN];
  430.     do
  431.     {                                /* get INLEN bytes from the input file */
  432.         nbytes3 = fread(buf, sizeof(char), INLEN, FILEin);
  433.         *fsize += nbytes3;
  434.  
  435.         if (nbytes3 == INLEN)
  436.         {   abLine[0] = chbytes3;                    /* store quantity char */
  437.             len = OUTLEN;
  438.         }
  439.         else
  440.         {   abLine[0] = sXXtable[nbytes3];           /* store quantity char */
  441.             for (i = nbytes3; i < INLEN; i++)  buf[i] = 0;
  442.             nbytes3 = (nbytes3 + 2) / 3;             /* take ceiling of div */
  443.             len = 4 * nbytes3;                        /* # of encoded bytes */
  444.             nbytes3 *= 3;         /* translate from 3-byte packets to bytes */
  445.         }
  446.  
  447.         for (i = nbytes3 - 3, j = len - 4; i >= 0; i -= 3, j -= 4)/* encode */
  448.         {
  449.             buf[j + 3] =
  450.                 sXXtable[buf[i + 2] & BIT6MASK];
  451.             buf[j + 2] =
  452.                 sXXtable[((buf[i+1] << 2) + (buf[i+2] >> 6)) & BIT6MASK];
  453.             buf[j + 1] =
  454.                 sXXtable[((buf[i] << 4)   + (buf[i+1] >> 4)) & BIT6MASK];
  455.             buf[j]     =
  456.                 sXXtable[(buf[i] >> 2) & BIT6MASK];
  457.         }
  458. #if defined(MSDOS)
  459.         buf[len++] = '\r';         /* file opened binary --> \r\n for MSDOS */
  460. #endif
  461.         buf[len++] = '\n';                     /* add end of line character */
  462.  
  463.         if (fwrite(abLine, len + 1, 1, FILEout) != 1)
  464.            message(ERROR, cLine, "write error on output file");
  465.         cLine++;                                   /* increment linecounter */
  466.  
  467.     } while (nbytes3 > 0 && cLine != mxlines);
  468.  
  469. return(nbytes3);
  470. }
  471.  
  472. #if defined(ANSI_DECL)
  473.   void encode(int mxlines)
  474. #else
  475.   encode(mxlines)  int mxlines;
  476. #endif
  477. {
  478.     int  i, fnum = 1;  char *outext;  long  fsize = 0;
  479.  
  480.     printf("\n%s --- %s ---> %s\n", sInfile, sMethod, sOutfile);
  481.  
  482.     fprintf(FILEout, "%s %s (%s)%s", sMethod, sVersion, SYSTEM_ID, EOL_STR);
  483.     fprintf(FILEout, "begin 644 %s%s", fbase(sInfile), EOL_STR);
  484.     cLine = 3;                         /* current line number in input file */
  485.     outext = fext(sOutfile);
  486.  
  487.     while (encode_file(&fsize, mxlines) > 0)
  488.     {
  489.         fclose(FILEout);
  490.         outext[3] = ++fnum % 10 + '0';  /* create new : increment extension */
  491.         if (fnum / 10 > 0)  outext[2] = fnum / 10 + '0';
  492.  
  493.         FILEout = fopen_w(sOutfile, sOutbuf, NO_CONFIRM, NCODE);
  494.  
  495.         printf("%*s --- %s ---> %s\n", strlen(sInfile), " ", sMethod, sOutfile);
  496.         fprintf(FILEout, "part %d%s", fnum, EOL_STR);
  497.         fprintf(FILEout, "begin 644 %s%s", fbase(sInfile), EOL_STR);
  498.         cLine = 3;
  499.     }
  500.     fprintf(FILEout,"end%s%ld bytes%s", EOL_STR, fsize, EOL_STR);
  501.     if (fnum > 0)  fprintf(FILEout,"encoded into %d file(s)%s", fnum, EOL_STR);
  502. }
  503. /*--------------------------- END encode -----------------------------------*/
  504.  
  505.  
  506. /*------------------------- decode -----------------------------------------
  507.  * decode_file skips undefined characters until the first normal character
  508.  *    is found in the input file. The line counter is incremented and the
  509.  *    line to be decoded is read into abLine.
  510.  *    Returns the # bytes (# after decoding, so 4 * nbytes / 3 when encoded)
  511.  *    in the line or EOF for eof (nothing more to decode).
  512.  *    A line could end in \r\n (MSDOS), \n (VMS/UNIX?), or _EOF (unexpected
  513.  *    end-of-file).
  514.  *    Emailing to Southampton led to ' '\r\n being the end of line,
  515.  *    reason why undefined chars are skipped.
  516.  * then it replaces the 4 byte packets (6-bits per byte) in abLine into 3 byte
  517.  *    packets (8-bits per byte), and writes it to the output file.
  518.  *--------------------------------------------------------------------------*/
  519. #if defined(ANSI_DECL)
  520.   int  recover(int i, int nbytes3, int len)
  521. #else
  522.   int  recover(i, nbytes3, len)  int i, nbytes3, len;
  523. #endif
  524. {
  525.     int  j, ch;
  526.                                                            /* line to short */
  527.     do
  528.     {   if (i >= len)  return(sXXtable[0]);/*no problem: at end of decoding */
  529.         if (piNNmap[abLine[i]] == EOF)
  530.         {   for ( ; i < len; i++)  abLine[i] = sXXtable[0];
  531.             message(WARNING, cLine, "unexpected end of file");
  532.             return(sXXtable[0]);                        /* return null char */
  533.         }
  534.         if (abLine[i] == '\n')
  535.         {
  536.             cLine++;                               /* increment linecounter */
  537.             if (nbytes3 == iNNlen)                 /* no: glue broken lines */
  538.                 message(WARNING, cLine - 1, "unexpected line break - glued");
  539.             else if (nbytes3 < iNNlen)
  540.             {   message(WARNING, cLine - 1, "unexpected end of line");
  541.                 for ( ; i < len; i++)  abLine[i] = sXXtable[0];
  542.                 return(sXXtable[0]);
  543.             }
  544.             else
  545.                 message(WARNING, cLine - 1, "file probably corrupted");
  546.         }
  547.         else if (abLine[i] >= ' ')
  548.             message(WARNING, cLine, "skipped illegal character \'%c\'", abLine[i]);
  549.         else
  550.             message(WARNING, cLine, "skipped illegal character %#x", abLine[i]);
  551.  
  552.                   /* now remove offending character, and add new one at end */
  553.         for (j = i ; j < len - 1; j++)  abLine[j] = abLine[j + 1];
  554.         if ( (ch = getc(FILEin)) == EOF)  ch = sXXtable[0];
  555.         abLine[j] = ch;
  556.  
  557.     } while (piNNmap[abLine[i]] < 0);
  558.  
  559. return(piNNmap[abLine[i]]);
  560. }
  561.  
  562. #if defined(ANSI_DECL)
  563.   int  decode_file(long *fsize)
  564. #else
  565.   int  decode_file(fsize)  long *fsize;
  566. #endif
  567. {
  568.     int  i, j, len, ch;  int  k1, k2, k3, k4;
  569.     int  nbytes3;       /* # decoded bytes (so 4 * nbytes / 3 when encoded) */
  570.  
  571.     if (chFirst == 0)  chFirst = getc(FILEin);
  572.     nbytes3 = piNNmap[chFirst];            /* read first quantity character */
  573.     if (nbytes3 == EOF)  return(EOF);
  574.  
  575.     do
  576.     {   len = (nbytes3 * 4) / 3 + (nbytes3 % 3 > 0);  /* # of encoded bytes */
  577.  
  578.         if (fread(abLine, len, 1, FILEin) < 1)
  579.             message(WARNING, cLine, "unexpected end of file");
  580.  
  581.         for (i = j = 0; i < nbytes3; i += 3, j += 4)     /* decode the line */
  582.         {
  583.             if ( (k1 = piNNmap[abLine[j]]) < 0)
  584.                 k1 = recover(j, nbytes3, len);
  585.             if ( (k2 = piNNmap[abLine[j + 1]]) < 0)
  586.                 k2 = recover(j + 1, nbytes3, len);
  587.             if ( (k3 = piNNmap[abLine[j + 2]]) < 0)
  588.                 k3 = recover(j + 2, nbytes3, len);
  589.             if ( (k4 = piNNmap[abLine[j + 3]]) < 0)
  590.                 k4 = recover(j + 3, nbytes3, len);
  591.             abLine[i]     = (k1 << 2) + (k2 >> 4);
  592.             abLine[i + 1] = (k2 << 4) + (k3 >> 2);
  593.             abLine[i + 2] = (k3 << 6) +  k4;
  594.         }
  595.                                                             /* and write it */
  596.         if (fwrite(abLine, nbytes3, 1, FILEout) != 1)
  597.             message(ERROR, cLine, "write error on output file");
  598.         *fsize += nbytes3;
  599.                                /* skip remaining characters on current line */
  600.         for (i = 0, ch = getc(FILEin); piNNmap[ch] >= 0; i++)
  601.             ch = getc(FILEin);
  602.         if (i > 0 && nbytes3 == iNNlen)/*no message for ending shorter line */
  603.             message(WARNING, cLine, "end of line expected");
  604.  
  605.         do                           /* locate first character on next line */
  606.         {   if (ch == '\n')  cLine++;              /* increment linecounter */
  607.             ch = getc(FILEin);
  608.         }  while ( (nbytes3 = piNNmap[ch]) == UNDEF_CH);
  609.  
  610.     } while (nbytes3 > 0);
  611.  
  612. return(nbytes3);     /* returns either 0 (last line) or EOF (more expected) */
  613. }
  614.  
  615.  
  616. #if defined(ANSI_DECL)
  617.   void  decode(void)
  618. #else
  619.   decode()
  620. #endif
  621. {
  622.     int  fnum = 1;  char *inext;  long  fsize = 0, osize = 0;
  623.     char dummy[80];
  624.  
  625.     printf("\n%s --- %s ---> %s ", sInfile, sMethod, sOutfile);
  626.  
  627. #if defined(VMS)
  628.     if (Stream_LF == TRUE)
  629.       printf(" [Stream_LF]\n");
  630.     else
  631.       printf(" [Variable length]\n");
  632. #else
  633.     printf("\n");
  634. #endif
  635.     inext = fext(sInfile);
  636.  
  637.     while (decode_file(&fsize) == EOF)
  638.     {
  639.         fclose(FILEin);
  640.         inext[3] = ++fnum % 10 + '0';     /* find next: increment extension */
  641.         if (fnum / 10 > 0)  inext[2] = fnum / 10 + '0';
  642.         
  643.         printf("%s --- %s --->\n", sInfile, sMethod);
  644.         FILEin = get_start(sInfile);          /* find start of encoded text */
  645.     }
  646.                                                      /* check trailing line */
  647.     fscanf(FILEin, " %s %ld", abLine, &osize);
  648.     cLine++;
  649.     if (strncmp(abLine, "end", 3) != 0)
  650.         message(WARNING, cLine, "end line not found");
  651.     if (osize > 0 && osize != fsize)
  652.     {   fscanf(FILEin, " %s", abLine);
  653.         if (abLine[0] != 'l')  message(WARNING, 0, "file size different");
  654.     }
  655. }
  656. /*--------------------------- END decode -----------------------------------*/
  657.  
  658.  
  659. /*----------------------------- main ---------------------------------------*/
  660. #if defined(ANSI_DECL)
  661.   main(int argc, char *argv[])
  662. #else
  663.   main(argc, argv)  int argc; char *argv[];
  664. #endif
  665. {
  666.     int  i, mxlines = -1;  char *ext, temp[80];
  667.  
  668.     printf("\n%s %s (%s), %s\n", sProgram, sVersion, SYSTEM_ID, sAuthor);
  669.  
  670.     if (--argc == 0 || strcmp(*++argv,"?") == 0)  /* check the command line */
  671.     {   for (i = 0; sUsage[i] != NULL; i++)  printf("%s\n",sUsage[i]);
  672.         return;                           /* return(0) gives message on VAX */
  673.     }
  674.     while (argc > 0)
  675.     {
  676.     if (**argv == '/')
  677.         {   if (*++*argv == 'u' || **argv == 'U')
  678.             {   sMethod[0] = sMethod[1] = 'U';
  679.                 for (i = 0; i < 64; i++)
  680.                     sXXtable[i] = sUUtable[i];    /* replace XXmap by UUmap */
  681.                 iXXlen = iUUlen;
  682.             }
  683.             else if (**argv == 's' || **argv == 'S') /* VAX-VMS Stream_LF */
  684.             {   Stream_LF = TRUE;
  685.             }
  686.             else if (isdigit(**argv))
  687.             {   mxlines = atoi(*argv);     /* max no of kilobytes in a file */
  688.                 mxlines = mxlines * 16;                        /* --> lines */
  689.             }
  690.         }
  691.         else if (*sInfile == '\0')
  692.             strcpy(sInfile, *argv);              /* copy name of input file */
  693.         else if (*sOutfile == '\0')
  694.             strcpy(sOutfile, *argv);          /* user specified output file */
  695.  
  696.         --argc;  ++argv;
  697.     }                        /* end of exploration of command line switches */
  698.  
  699.     for (i = 0; sOutfile[i] != '\0'; i++)  sOutfile[i] = tolower(sOutfile[i]);
  700.     for (i = 0;  sInfile[i] != '\0'; i++)   sInfile[i] = tolower( sInfile[i]);
  701.     ext = fext(sInfile);
  702.  
  703.     if (*ext == '\0' || strncmp(ext, sDefault_ext, 4) == 0
  704.         || strncmp(ext, ".xxe", 4) == 0 || strncmp(ext, ".uue", 4) == 0)
  705.     {
  706.         sMethod[2] = 'd';  sMethod[3] = 'e';
  707.         if (*ext == '\0')  strcat(sInfile, sDefault_ext);/* add default ext */
  708.         FILEin = fopen_r(sInfile, sInbuf);
  709.  
  710.         get_outfname(FILEin, sInfile, temp);/* temp holds recorded sOutfile */
  711.         if (*sOutfile != '\0')       /* yes: user override of recorded name */
  712.             message(WARNING, 0, "%s specified outfile as %s", sInfile, temp);
  713.         else
  714.             strcpy(sOutfile, temp);      /* store recorded name in sOutfile */
  715.         FILEout = fopen_w(sOutfile, sOutbuf, CONFIRM, DCODE);
  716.  
  717.         decode();
  718.     }
  719.     else
  720.     {
  721.         FILEin = fopen_r(sInfile, sInbuf);
  722.  
  723.         if (*sOutfile == '\0')       /* no output file name on command line */
  724.             strcpy(sOutfile, sInfile);
  725.         strcpy(fext(sOutfile), sDefault_ext);   /* replace or add extension */
  726.         if (strcmp(sOutfile, sInfile) == 0)
  727.             message(ERROR, 0, "input and output filename must differ");
  728.         FILEout = fopen_w(sOutfile, sOutbuf, CONFIRM, NCODE);
  729.  
  730.         encode(mxlines);
  731.     }
  732. }
  733.